package com.diy.task.common.base;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.IEnum;
import com.baomidou.mybatisplus.extension.service.IService;
import com.diy.task.common.utils.StringTools;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Field;

/**
 * @Usage: 通用Controller（增删改查）
 * @Author: gjq
 * @Date: 2019/3/4 7:28 PM
 */
@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT, RequestMethod.OPTIONS}, origins = "*", maxAge = 3600)
public abstract class BaseController<S extends IService<T>, T extends BaseEntity> {

    @Autowired
    protected S service;

    /**
     * 根据id获取实体对象
     * @param id
     * @return
     */
    @ApiOperation(value = "根据id获取实体对象" , notes = "code：0 找到记录，1未找到记录")
    @GetMapping("get/{id}")
    @ResponseBody
    public BaseResult getInfo(@PathVariable Long id) {
        T t = service.getById(id);
        BaseResult baseResult = t == null ? BaseResult.error(1,"未找到该记录") : BaseResult.ok(t);
        return baseResult;
    }

    /**
     * 保存记录
     * @param T t
     * @return 操作是否成功
     */
    @ApiOperation(value = "保存记录", notes = "传入id表示更新，未传入id表示插入")
    @PostMapping("save")
    @ResponseBody
    public BaseResult save (@RequestBody T t){
        return BaseResult.ok(service.saveOrUpdate(t));
    }

    /**
     * 删除记录
     * @param T t
     * @return 操作是否成功
     */
    @ApiOperation(value = "删除记录")
    @PostMapping("delete")
    @ResponseBody
    public BaseResult delete (@RequestBody T t) {
        return BaseResult.ok(service.removeById(t.getId()));
    }

    /**
     * 分页查找记录
     * @param SmartPage<T> spage 示例：{"search":{"creator":"admin1"},"ascs":[],"descs":[],"size":2,"current":1}
     * @return 返回查找结果
     */
    @ApiOperation(value = "获取分页列表", notes = "传入参数：search查询条件实体，ascs升序条件，descs降序条件，size每页大小，current当前页。")
    @PostMapping("list")
    @ResponseBody
    public BaseResult gerListByPage(@RequestBody SmartPage<T> spage){
        Wrapper queryWrapper = initQueryWrapper(spage);
        return BaseResult.ok(service.page(spage, queryWrapper));
    }

    /**
     * 构造初始化wrapper，spage为通用查询格式
     * @param spage
     * @return 返回查询条件的封装
     * todo 将查询条件装配部分拆分出去
     */
    public QueryWrapper<T> initQueryWrapper(SmartPage<T> spage) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        if (spage.getSearch() != null) {
            Class search = spage.getSearch().getClass();
            Field[] fields;
            Field[] classFields = search.getDeclaredFields();

            // getDeclaredFields只能获取到本类的属性，不能获取父类属性，专门对父类进行处理
            if(search.getSuperclass() != null){
                Field[] superFields = search.getSuperclass().getDeclaredFields();
                fields= new Field[classFields.length+superFields.length];
                System.arraycopy(classFields,0,fields,0,classFields.length);
                System.arraycopy(superFields,0,fields,classFields.length,superFields.length);
            }else {
                fields= classFields;
            }
            for (int i = 0; i < fields.length; i++) {
                try {
                    fields[i].setAccessible(true);
                    //判断如果是临时字段则不进行查询
                    if (fields[i].getAnnotation(TableField.class) != null && !fields[i].getAnnotation(TableField.class).exist()) {
                        fields[i].setAccessible(false);
                        continue;
                    }

                    Object value = fields[i].get(spage.getSearch());
                    if (null != value && !"".equals(value) && fields[i].getName() != "serialVersionUID") {
                        String fieldname = StringTools.underscoreName(fields[i].getName());
                        //设置对于不同类型的默认处理
                        if (fields[i].getType().isEnum()) {
                            wrapper.eq(fieldname, ((IEnum) value).getValue());
                        } else if ("java.lang.String".equals(fields[i].getType().getName())) {
                            wrapper.eq(fieldname, value.toString());
                        }if ("java.lang.Double".equals(fields[i].getType().getName())) {
                            wrapper.eq(fieldname, value);
                        } else {
                            wrapper.eq(fieldname, value.toString());
                        }
                    }
                    fields[i].setAccessible(false);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }

        return wrapper;
    }
}
